package com.example.easypan.controller;

import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.example.easypan.change.FileCategoryUtils;

import com.example.easypan.common.Page;
import com.example.easypan.common.Result;
import com.example.easypan.pojo.FileInfo;
import com.example.easypan.pojo.PointFileIndexVo;
import com.example.easypan.service.impl.FileInfoServiceImpl;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;


/**
 * 功能：
 * 作者：cyan
 * 日期：2025/2/5 下午4:54
 */
@Slf4j
@RestController
@RequestMapping("/file")
public class FileController {

    //系统路径+文件存放
    // D:\编程项目\java\20250129_laoluo\files
    private static final String ROOT_PATH =  System.getProperty("user.dir") + File.separator + "files";

    @Resource
    private FileInfoServiceImpl fileInfoService;

    @GetMapping("/list")
    public Result getAll()
    {
        LambdaQueryWrapper<FileInfo> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(FileInfo::getDelFlag,2);
        List<FileInfo> list = fileInfoService.list(queryWrapper);
        return Result.success(list);
    }



    //加上点设置可以读取后缀
    @GetMapping("/download/{fileName:.+}")
    public void download(@PathVariable String fileName, HttpServletResponse response) throws IOException {
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件下载
        String filePath = ROOT_PATH  + File.separator + fileName;

        if (!FileUtil.exist(filePath)) {
            return;
        }
        byte[] bytes = FileUtil.readBytes(filePath);
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(bytes);  // 数组是一个字节数组，也就是文件的字节流数组
        outputStream.flush();
        outputStream.close();
    }

    //文件普通上传
    @PostMapping("/upload1")
    public Result upload1(MultipartFile file,Integer folderId) throws IOException, NoSuchAlgorithmException {
        String originalFilename = file.getOriginalFilename();  // 获取文件的原始名称
        String mainName = FileUtil.mainName(originalFilename);//文件名
        String extName = FileUtil.extName(originalFilename);    // 获取文件的扩展名
        if (!FileUtil.exist(ROOT_PATH)) {
            FileUtil.mkdir(ROOT_PATH);  // 如果当前文件的父级目录不存在，就创建
        }

        //计算文件的 MD5 值
        String fileHash = calculateFileMd5(file);

        // 秒传
        // 检查文件是否已经上传过
        String uploadedFilePath = ROOT_PATH + File.separator + mainName + "." + extName;
        File uploadedFile = new File(uploadedFilePath);
        if (uploadedFile.exists()) {
            // 文件已经上传过，返回秒传链接
            String url = "http://localhost:9090/file/download/" + mainName + "." + extName;

            //重命名存储到数据库中
            long fileSize = uploadedFile.length();
            String userId = "exampleUserId";  // 此处替换为实际的用户ID
            Date createTime = new Date();
            mainName=System.currentTimeMillis() + "_" + mainName;
            insertFileInfo(userId, fileHash, mainName, extName, fileSize,
                    uploadedFilePath, createTime,url,folderId);

            return Result.success(url,"秒传，无需解码");
        }
        // 文件不存在，开始上传
        File targetFile = new File(uploadedFilePath);

        // 存储文件到本地的磁盘里面去
        file.transferTo(targetFile);

        // 生成文件下载链接
        String url = "http://localhost:9090/file/download/" + mainName + "." + extName;


        //插入数据库
        long fileSize = targetFile.length();
        String userId = "exampleUserId";  // 此处替换为实际的用户ID
        Date createTime = new Date();
        insertFileInfo(userId, fileHash, mainName, extName, fileSize, uploadedFilePath, createTime,url,folderId);


        return Result.success(url);  // 返回文件下载链接
    }

    //分片上传
    @PostMapping("/singleFilePartUpload")
    public Result singleFilePartUpload(@RequestParam("filePart") MultipartFile filePart,
                                       @RequestParam("partIndex") Integer partIndex,
                                       @RequestParam("partNum") Integer partNum,
                                       @RequestParam("fileName") String fileName,
                                       @RequestParam("fileUid") String fileUid,
                                       @RequestParam("folderId") int folderId,
                                       @RequestParam("fileMd5") String fileMd5,
                                       @RequestParam("fileSize") Long fileSize) {
        log.info("单文件分片上传,总片数:{},分片数:{},文件名:{},大小:{},uid:{}", partNum, partIndex, fileName, filePart.getSize(), fileUid);
        Result result = fileInfoService.singleFilePartUpload(filePart, partIndex, partNum, fileName, fileUid,folderId,fileMd5,fileSize);
        return result;
    }


    //断点续传
    @PostMapping("/checkUploadFileIndex")
    public Result checkUploadFileIndex(@RequestBody PointFileIndexVo pointFileIndexVo) {
        log.info("检测服务器中文件上传进度，{}", pointFileIndexVo);
        Result result = fileInfoService.checkUploadFileIndex(pointFileIndexVo);
        return result;
    }

    /**
     * 单文件(分片)断点上传
     *
     * @param filePart 单次分片的文件
     * @param fileInfo 当前相关信息
     */
    @PostMapping("/singleFilePartPointUpload")
    public Result singleFilePartPointUpload(@RequestParam("filePart") MultipartFile filePart,
                                            @RequestParam("fileInfo") String fileInfo) {
        Result result = fileInfoService.singleFilePartPointUpload(filePart, fileInfo);
        return result;
    }

    //大文件的下载
    //加上点设置可以读取后缀
    @GetMapping("/downloadBig/{fileName:.+}")
    public void download1(@PathVariable String fileName, HttpServletResponse response) throws IOException {
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件下载
        String filePath = System.getProperty("user.dir") + "\\file\\"+fileName;//文件存放路径

        if (!FileUtil.exist(filePath)) {
            return;
        }
        byte[] bytes = FileUtil.readBytes(filePath);
        ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(bytes);  // 数组是一个字节数组，也就是文件的字节流数组
        outputStream.flush();
        outputStream.close();
    }

    private void insertFileInfo(String userId, String fileHash, String mainName, String extName,
                                long fileSize, String filePath, Date createTime,String url,int folderId) {
        // 创建 FileInfo 实体对象
        FileInfo fileInfo = new FileInfo();
        fileInfo.setUserId(userId);
        fileInfo.setFileMd5(fileHash);
        fileInfo.setFileSize(fileSize);
        fileInfo.setFileName(mainName + "." + extName);
        fileInfo.setFileUrl(url);
        fileInfo.setFilePath(filePath);
        fileInfo.setCreateTime(createTime);
        fileInfo.setFolderType(0);  // 0: 文件
        fileInfo.setFolderId(folderId);
        int type= FileCategoryUtils.getFileCategory(extName);
        fileInfo.setFileCategory(type);  // 识别文件类型
        fileInfo.setDelFlag(2);  // 2: 正常
        fileInfoService.save(fileInfo);
    }



    // 计算文件的 MD5 值
    private String calculateFileMd5(MultipartFile file) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (InputStream is = file.getInputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                md.update(buffer, 0, len);
            }
        }
        byte[] md5Bytes = md.digest();
        StringBuilder hexString = new StringBuilder();
        for (byte b : md5Bytes) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString();
    }


    @GetMapping("/page")
    public Result selectPage(@RequestParam Integer pageNum,@RequestParam Integer pageSize,
                            @RequestParam Integer pageFolderId)
    {
        Page<FileInfo> page=new Page<>();
        //当前页面
        Integer cur=(pageNum-1)*pageSize;
        List<FileInfo> list= fileInfoService.selectPage(cur,pageSize,pageFolderId);
        Integer count=fileInfoService.getCount();
        page.setList(list);
        page.setTotal(count);

        return Result.success(page);
    }
    
    @PostMapping("/rename")
    public Result ReName(@RequestBody FileInfo fileInfo)
    {
        String reName=fileInfo.getFileName();
        Integer fileId = fileInfo.getFileId();

        // 查找文件是否存在
        LambdaQueryWrapper<FileInfo> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(FileInfo::getFileId,fileId);
        FileInfo byId = fileInfoService.getOne(lambdaQueryWrapper);

        byId.setFileName(reName);

        boolean flag=fileInfoService.update(byId,lambdaQueryWrapper);

        if(flag)
        {
            return Result.success("更新成功");
        }
        else
        {
            return Result.error("更新失败");
        }

    }

    //删除文件(写入回收站)
    @PostMapping("/toRecycle/{id}")
    public Result toRecycle(@PathVariable Integer id)
    {
        LambdaUpdateWrapper<FileInfo> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.setSql("del_flag=1").eq(FileInfo::getFileId,id);
        boolean flag=fileInfoService.update(updateWrapper);

        if(flag)
        {
            return Result.success("删除成功");
        }
        else
        {
            return Result.error("删除失败");
        }
    }

    //文件移动
    @PostMapping("/moveFile")
    public Result moveFile(@RequestParam("folderId") Integer folderId,@RequestParam("selectmoveFileId") Integer selectmoveFileId)
    {
        LambdaQueryWrapper<FileInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileId,selectmoveFileId);

        FileInfo fileInfo=fileInfoService.getOne(wrapper);

        fileInfo.setFolderId(folderId);
        boolean success = fileInfoService.update(fileInfo,wrapper);

        return Result.success(fileInfo);
    }

    @PostMapping("/videoList")
    public Result getVideoList()
    {
        LambdaQueryWrapper<FileInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileCategory,1)
                .eq(FileInfo::getDelFlag,2)
                .orderByDesc(FileInfo::getCreateTime);

        List<FileInfo> list = fileInfoService.list(wrapper);

        return Result.success(list);
    }

    @PostMapping("/wordList")
    public Result getWordList()
    {
        LambdaQueryWrapper<FileInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getFileCategory,4)
                .eq(FileInfo::getDelFlag,2)
                .orderByDesc(FileInfo::getCreateTime); // 按照创建时间降序排序


        List<FileInfo> list = fileInfoService.list(wrapper);

        return Result.success(list);
    }

    @PostMapping("/recycleList")
    public Result getrecycleList()
    {
        LambdaQueryWrapper<FileInfo> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(FileInfo::getDelFlag,1)
                .orderByDesc(FileInfo::getCreateTime); // 按照创建时间降序排序


        List<FileInfo> list = fileInfoService.list(wrapper);

        return Result.success(list);
    }

    @PostMapping("/recover/{id}")
    public Result recover(@PathVariable Integer id)
    {
        LambdaUpdateWrapper<FileInfo> updateWrapper=new LambdaUpdateWrapper<>();
        updateWrapper.setSql("del_flag=2").eq(FileInfo::getFileId,id);
        boolean flag=fileInfoService.update(updateWrapper);

        if(flag)
        {
            return Result.success("恢复成功");
        }
        else
        {
            return Result.error("恢复失败");
        }
    }




}